
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */ 
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

#include "OGLVisu.h"
#include <QGLWidget>

#include <math.h>

#include <glut.h>

OGLVisu* OGLVisu::_instance = 0;

OGLVisu::OGLVisu()
{
	createSphere();
	_discQuadric = gluNewQuadric();
}

OGLVisu::~OGLVisu()
{}

OGLVisu& OGLVisu::getInstance()
{
	if (_instance == 0)
		_instance = new OGLVisu();

	return *_instance;
}

void OGLVisu::close()
{
	if(_instance != 0)
	{
		delete _instance;
		_instance = 0;
	}
}

void OGLVisu::addPointLight(unsigned int lightID, const CVector3f& position, 
							const CVector3f& attenuation, Material& m)
{
	int id = GL_LIGHT0 + lightID;

	glEnable(id);

	float light_position[4];
	light_position[0] = position.x;
	light_position[1] = position.y;
	light_position[2] = position.z;
	light_position[3] = 1;

	/*float diffuseLight[] = {1.f, 1.f, 1.f, 1.f};
	glLightfv(id, GL_DIFFUSE, diffuseLight);

	float ambientLight[] = {0.f, 0.f, 0.f, 1.f};
	glLightfv(id, GL_AMBIENT, ambientLight);

	float specularLight[] = {1.f, 1.f, 1.f, 1.f};
	glLightfv(id, GL_SPECULAR, specularLight);*/
	glLightfv(id, GL_DIFFUSE, m.getDiffuse());
	glLightfv(id, GL_AMBIENT, m.getAmbient());
	glLightfv(id, GL_SPECULAR, m.getSpecular());

	glLightf(id, GL_CONSTANT_ATTENUATION, attenuation.x);
	glLightf(id, GL_LINEAR_ATTENUATION, attenuation.y);
	glLightf(id, GL_QUADRATIC_ATTENUATION, attenuation.z);

	glLightfv(id, GL_POSITION, light_position);
	glLightf(id, GL_SPOT_CUTOFF, 180);
}

//add a directional light to the scene
void OGLVisu::addDirectionalLight(unsigned int lightID, const CVector3f& direction, Material& m)
{
	int id = GL_LIGHT0 + lightID;

	glEnable(id);

	float light_position[4];
	light_position[0] = direction.x;
	light_position[1] = direction.y;
	light_position[2] = direction.z;
	light_position[3] = 0;

	/*float diffuseLight[] = {1.f, 1.f, 1.f, 1.f};
	glLightfv(id, GL_DIFFUSE, diffuseLight);

	float ambientLight[] = {0.f, 0.f, 0.f, 1.f};
	glLightfv(id, GL_AMBIENT, ambientLight);

	float specularLight[] = {1.f, 1.f, 1.f, 1.f};
	glLightfv(id, GL_SPECULAR, specularLight);*/
	glLightfv(id, GL_DIFFUSE, m.getDiffuse());
	glLightfv(id, GL_AMBIENT, m.getAmbient());
	glLightfv(id, GL_SPECULAR, m.getSpecular());

	glLightfv(id, GL_POSITION, light_position);
}

//add a spot light to the scene
void OGLVisu::addSpotLight(unsigned int lightID, const CVector3f& position, const CVector3f& direction, 
	const CVector3f& attenuation, float cutOff, float exponent, Material& m)
{
	int id = GL_LIGHT0 + lightID;

	glEnable(id);

	float light_position[4];
	light_position[0] = position.x;
	light_position[1] = position.y;
	light_position[2] = position.z;
	light_position[3] = 1;

	//float diffuseLight[] = {1.f, 1.f, 1.f, 1.f};
	//glLightfv(id, GL_DIFFUSE, diffuseLight);
	glLightfv(id, GL_DIFFUSE, m.getDiffuse());

	//float ambientLight[] = {0.f, 0.f, 0.f, 1.f};
	//glLightfv(id, GL_AMBIENT, ambientLight);
	glLightfv(id, GL_AMBIENT, m.getAmbient());

	//float specularLight[] = {1.f, 1.f, 1.f, 1.f};
	//glLightfv(id, GL_SPECULAR, specularLight);
	glLightfv(id, GL_SPECULAR, m.getSpecular());

	glLightfv(id, GL_POSITION, light_position);

	float light_direction[4];
	light_direction[0] = direction.x;
	light_direction[1] = direction.y;
	light_direction[2] = direction.z;
	light_direction[3] = 1;

	glLightfv(id, GL_SPOT_DIRECTION, light_direction);

	glLightf(id, GL_CONSTANT_ATTENUATION, attenuation.x);
	glLightf(id, GL_LINEAR_ATTENUATION, attenuation.y);
	glLightf(id, GL_QUADRATIC_ATTENUATION, attenuation.z);

	glLightf(id, GL_SPOT_CUTOFF, cutOff);
	glLightf(id, GL_SPOT_EXPONENT, exponent);
}

//add the global ambient light
void OGLVisu::addGlobalAmbientLight(float* light)
{
	//ambiant light
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light);
}

void OGLVisu::drawBox(float width, float height, float depth)
{
	float offsetX = width / 2;
	float offsetY = height / 2;
	float offsetZ = depth / 2;
	
	
	glBegin(GL_QUADS);
		//front face
		glNormal3f(0.f, 0.f, 1.f);
		glVertex3f(offsetX, -offsetY, offsetZ);
		glVertex3f(offsetX, offsetY, offsetZ);
		glVertex3f(-offsetX, offsetY, offsetZ);
		glVertex3f(-offsetX, -offsetY, offsetZ);
	
		//left face
		glNormal3f(-1.f, 0.f, 0.f);
		
		glVertex3f(-offsetX, -offsetY, offsetZ);
		glVertex3f(-offsetX, offsetY, offsetZ);
		glVertex3f(-offsetX, offsetY, -offsetZ);
		glVertex3f(-offsetX, -offsetY, -offsetZ);

		//right face;
		glNormal3f(1.f, 0.f, 0.f);
		glVertex3f(offsetX, -offsetY, -offsetZ);
		glVertex3f(offsetX, offsetY, -offsetZ);
		glVertex3f(offsetX, offsetY, offsetZ);
		glVertex3f(offsetX, -offsetY, offsetZ);


		//bottom face
		glNormal3f(0.f, -1.f, 0.f);
		glVertex3f(-offsetX, -offsetY, -offsetZ);
		glVertex3f(offsetX, -offsetY, -offsetZ);
		glVertex3f(offsetX, -offsetY, offsetZ);
		glVertex3f(-offsetX, -offsetY, offsetZ);

		//top face
		glNormal3f(0.f, 1.f, 0.f);
		glVertex3f(-offsetX, offsetY, offsetZ);
		glVertex3f(offsetX, offsetY, offsetZ);
		glVertex3f(offsetX, offsetY, -offsetZ);
		glVertex3f(-offsetX, offsetY, -offsetZ);

		//back face
		glNormal3f(0.f, 0.f, -1.f);
		glVertex3f(-offsetX, -offsetY, -offsetZ);
		glVertex3f(-offsetX, offsetY, -offsetZ);
		glVertex3f(offsetX, offsetY, -offsetZ);
		glVertex3f(offsetX, -offsetY, -offsetZ);
	glEnd();
}

//draw a sphere
void OGLVisu::drawSphere(float radius)
{  
	gluSphere(_sphereQuadric, radius, 20, 20);
}

//draw a cylinder
void OGLVisu::drawCylinder(float radius, float height)
{

	glPushMatrix();
		glRotatef(-90, 1, 0, 0);
		gluCylinder(_discQuadric, radius, radius, height, 20, 20);
		gluDisk(_discQuadric, 0, radius, 20, 20);

		glPushMatrix();
			glTranslatef(0, 0, height);
			gluDisk(_discQuadric, 0, radius, 20, 20);
		glPopMatrix();
	glPopMatrix();
}

//draw a cone
void OGLVisu::drawCone(float radius, float height)
{
	glPushMatrix();
		glRotatef(-90, 1, 0, 0);
		gluCylinder(_discQuadric, radius, 0, height, 20, 20);
		gluDisk(_discQuadric, 0, radius, 20, 20);
	glPopMatrix();
}

//draw a torus
void OGLVisu::drawTorus(float smallRadius, float bigRadius)
{
	glPushMatrix();
		glutSolidTorus (smallRadius, bigRadius, 20, 20);
	glPopMatrix();
}

//draw a triangle and calculate the it's normal to render it correctly
void OGLVisu::drawTriangle(const CVector3f& v1, const CVector3f& v2, const CVector3f& v3)
{
	CVector3f e1 = v1 - v2;
	CVector3f e2 = v1 - v3;
	CVector3f n = e1.cross(e2);
	n.normalize();

	glBegin(GL_TRIANGLES);
		glNormal3f(n.x, n.y, n.z);
		glVertex3f(v1.x, v1.y, v1.z);
		glVertex3f(v2.x, v2.y, v2.z);
		glVertex3f(v3.x, v3.y, v3.z);
	glEnd();
}

//draw a triangle
void OGLVisu::drawTriangle(const CVector3f& v1, const CVector3f& v2, const CVector3f& v3, const CVector3f& n)
{
	glBegin(GL_TRIANGLES);
		glNormal3f(n.x, n.y, n.z);
		glVertex3f(v1.x, v1.y, v1.z);
		glVertex3f(v2.x, v2.y, v2.z);
		glVertex3f(v3.x, v3.y, v3.z);
	glEnd();
}

//draw the translation mark
void OGLVisu::drawTranslationMark(const CVector3f& hoovered)
{
	//save GL_FRONT_AND_BACK mode
	int wireFrameMode = 0;
	glGetIntegerv(GL_FRONT_AND_BACK, &wireFrameMode);

	//set fill mode
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

	//disable the lights
	glDisable(GL_LIGHTING);

	const float HOOVERSIZE = 5;
	//X coorindate
	if(hoovered.x != 0)
		glLineWidth(HOOVERSIZE);
	else
		glLineWidth(2);
	glBegin(GL_LINES);
		glColor3f(1, 0, 0);
		glVertex3f(0, 0, 0);
		glVertex3f(1, 0, 0);

		glVertex3f(1, 0, 0);
		glVertex3f(0.9f, 0.1f, 0);

		glVertex3f(1, 0, 0);
		glVertex3f(0.9f, -0.1f, 0);
	glEnd();

	//Y coorindate
	if(hoovered.y != 0)
		glLineWidth(HOOVERSIZE);
	else
		glLineWidth(2);
	glBegin(GL_LINES);
		glColor3f(0, 1, 0);
		glVertex3f(0, 0, 0);
		glVertex3f(0, 1, 0);

		glVertex3f(0, 1, 0);
		glVertex3f(-0.1f, 0.9f, 0);

		glVertex3f(0, 1, 0);
		glVertex3f(0.1f, 0.9f, 0);
	glEnd();

	//Z coorindate
	if(hoovered.z != 0)
		glLineWidth(HOOVERSIZE);
	else
		glLineWidth(2);
	glBegin(GL_LINES);
		
		glColor3f(0, 0, 1);
		glVertex3f(0, 0, 0);
		glVertex3f(0, 0, 1);

		glVertex3f(0, 0, 1);
		glVertex3f(-0.1f, 0, 0.9f);

		glVertex3f(0, 0, 1);
		glVertex3f(0.1f, 0, 0.9f);
	glEnd();

	//reset the line width
	glLineWidth(2);

	//restart the lights
	glEnable(GL_LIGHTING);

	//reset GL_FRONT_AND_BACK mode
	glPolygonMode( GL_FRONT_AND_BACK, wireFrameMode );
}

//draw the rotation mark
void OGLVisu::drawRotationMark(const CVector3f& hoovered, float radius, const CVector3f& rotation)
{
	//disable the lights
	glDisable(GL_LIGHTING);

	const float SIZE = 0.2f;
	const float HOOVERSIZE = 0.3f;

	//X rotation
	glPushMatrix();
		glRotatef(90, 0, 1, 0);
		glColor3f(1, 0, 0);
		if(hoovered.x == 0)
			gluDisk(_discQuadric, radius - SIZE, radius, 20, 20);
		else
			gluDisk(_discQuadric, radius - HOOVERSIZE, radius, 20, 20);
	glPopMatrix();

	//Y rotation
	glPushMatrix();
		glRotatef(90, 1, 0, 0);
		glRotatef(rotation.x, 1, 0, 0);
		glColor3f(0, 1, 0);
		if(hoovered.y == 0)
			gluDisk(_discQuadric, radius - SIZE, radius, 20, 20);
		else
			gluDisk(_discQuadric, radius - HOOVERSIZE, radius, 20, 20);
	glPopMatrix();

	//Z rotation
	glPushMatrix();
		glRotatef(rotation.x, 1, 0, 0);
		glRotatef(rotation.y, 0, 1, 0);
		glColor3f(0, 0, 1);
		if(hoovered.z == 0)
			gluDisk(_discQuadric, radius - SIZE, radius, 20, 20);
		else
			gluDisk(_discQuadric, radius - HOOVERSIZE, radius, 20, 20);
	glPopMatrix();

	//enable the lights
	glEnable(GL_LIGHTING);
}

//draw the scale mark
void OGLVisu::drawScaleMark(const CVector3f& hoovered)
{
	//save GL_FRONT_AND_BACK mode
	int wireFrameMode = 0;
	glGetIntegerv(GL_FRONT_AND_BACK, &wireFrameMode);

	//set fill mode
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	glLineWidth(1);
	//disable the lights
	glDisable(GL_LIGHTING);

	//draw the weird polygon
	glColor3f(1, 1, 0);
	glBegin(GL_LINES);
		glVertex3f(1, 0, 0);
		glVertex3f(0, 0, 0);

		glVertex3f(0, 1, 0);
		glVertex3f(0, 0, 0);

		glVertex3f(0, 0, 1);
		glVertex3f(0, 0, 0);

		glVertex3f(1, 0, 0);
		glVertex3f(0, 1, 0);

		glVertex3f(0, 1, 0);
		glVertex3f(0, 0, 1);

		glVertex3f(0, 0, 1);
		glVertex3f(1, 0, 0);

		glVertex3f(0.7f, 0, 0);
		glVertex3f(0, 0.7f, 0);

		glVertex3f(0, 0.7f, 0);
		glVertex3f(0, 0, 0.7f);

		glVertex3f(0, 0, 0.7f);
		glVertex3f(0.7f, 0, 0);

		glVertex3f(0.3f, 0, 0);
		glVertex3f(0, 0.3f, 0);

		glVertex3f(0, 0.3f, 0);
		glVertex3f(0, 0, 0.3f);

		glVertex3f(0, 0, 0.3f);
		glVertex3f(0.3f, 0, 0);
	glEnd();

	const float HOOVERSIZE = 5;
	//X arrow
	if(hoovered.x != 0)
		glLineWidth(HOOVERSIZE);
	else
		glLineWidth(2);
	glPushMatrix();
		glTranslatef(1, 0, 0);
		glBegin(GL_LINES);
			glColor3f(1, 0, 0);
			glVertex3f(0, 0, 0);
			glVertex3f(1, 0, 0);

			glVertex3f(1, 0, 0);
			glVertex3f(0.9f, 0.1f, 0);

			glVertex3f(1, 0, 0);
			glVertex3f(0.9f, -0.1f, 0);
		glEnd();
	glPopMatrix();

	//Y arrow
	if(hoovered.y != 0)
		glLineWidth(HOOVERSIZE);
	else
		glLineWidth(2);
	glPushMatrix();
		glTranslatef(0, 1, 0);
		glBegin(GL_LINES);
			glColor3f(0, 1, 0);
			glVertex3f(0, 0, 0);
			glVertex3f(0, 1, 0);

			glVertex3f(0, 1, 0);
			glVertex3f(-0.1f, 0.9f, 0);

			glVertex3f(0, 1, 0);
			glVertex3f(0.1f, 0.9f, 0);
		glEnd();
	glPopMatrix();

	//Z arrow
	if(hoovered.z != 0)
		glLineWidth(HOOVERSIZE);
	else
		glLineWidth(2);

	glPushMatrix();
		glTranslatef(0, 0, 1);
		glBegin(GL_LINES);
			glColor3f(0, 0, 1);
			glVertex3f(0, 0, 0);
			glVertex3f(0, 0, 1);

			glVertex3f(0, 0, 1);
			glVertex3f(-0.1f, 0, 0.9f);

			glVertex3f(0, 0, 1);
			glVertex3f(0.1f, 0, 0.9f);
		glEnd();
	glPopMatrix();


	//reset the line width
	glLineWidth(2);

	//restart the lights
	glEnable(GL_LIGHTING);

	//reset GL_FRONT_AND_BACK mode
	glPolygonMode( GL_FRONT_AND_BACK, wireFrameMode );
}

//draw a simple rotation mark
void OGLVisu::drawSimpleRotationMark(bool hoover, float radius)
{
	const float SIZE = 0.2f;
	const float HOOVERSIZE = 0.3f;

	//disable the lights
	glDisable(GL_LIGHTING);

	//draw the mark
	glPushMatrix();
		if(!hoover)
			gluDisk(_discQuadric, radius - SIZE, radius, 20, 20);
		else
			gluDisk(_discQuadric, radius - HOOVERSIZE, radius, 20, 20);
	glPopMatrix();

	//enable the lights
	glEnable(GL_LIGHTING);
}

//draw the box which surround the selected object
void OGLVisu::drawSelectionBox(float width, float height, float depth)
{
	//save GL_FRONT_AND_BACK mode
	int wireFrameMode = 0;
	glGetIntegerv(GL_POLYGON_MODE, &wireFrameMode);

	//set fill mode
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

	//disable the lights
	glDisable(GL_LIGHTING);
	glLineWidth(1);

	//calculate bound
	float absMaxX = width / 2;
	float absMaxY = height / 2;
	float absMaxZ = depth / 2;

	//calculate the length : if greater than the box itself, decrease the length
	float length = 1;
	if (length > width)
		length = width;
	if (length > height)
		length = height;
	if (length > depth)
		length = depth;

	//draw the marks
	glBegin(GL_LINES);
		glColor3f(1, 1, 1);
		
		//front, lower left corner
		glVertex3f(-absMaxX, -absMaxY, absMaxZ);
		glVertex3f(-absMaxX + length, -absMaxY, absMaxZ);
		glVertex3f(-absMaxX, -absMaxY, absMaxZ);
		glVertex3f(-absMaxX, -absMaxY + length, absMaxZ);
		glVertex3f(-absMaxX, -absMaxY, absMaxZ);
		glVertex3f(-absMaxX, -absMaxY, absMaxZ - length);

		//front, lower right corner
		glVertex3f(absMaxX, -absMaxY, absMaxZ);
		glVertex3f(absMaxX - length, -absMaxY, absMaxZ);
		glVertex3f(absMaxX, -absMaxY, absMaxZ);
		glVertex3f(absMaxX, -absMaxY + length, absMaxZ);
		glVertex3f(absMaxX, -absMaxY, absMaxZ);
		glVertex3f(absMaxX, -absMaxY, absMaxZ - length);

		//front, upper left corner
		glVertex3f(-absMaxX, absMaxY, absMaxZ);
		glVertex3f(-absMaxX + length, absMaxY, absMaxZ);
		glVertex3f(-absMaxX, absMaxY, absMaxZ);
		glVertex3f(-absMaxX, absMaxY - length, absMaxZ);
		glVertex3f(-absMaxX, absMaxY, absMaxZ);
		glVertex3f(-absMaxX, absMaxY, absMaxZ - length);

		//front, upper right corner
		glVertex3f(absMaxX, absMaxY, absMaxZ);
		glVertex3f(absMaxX - length, absMaxY, absMaxZ);
		glVertex3f(absMaxX, absMaxY, absMaxZ);
		glVertex3f(absMaxX, absMaxY - length, absMaxZ);
		glVertex3f(absMaxX, absMaxY, absMaxZ);
		glVertex3f(absMaxX, absMaxY, absMaxZ - length);

		//back, lower left corner
		glVertex3f(-absMaxX, -absMaxY, -absMaxZ);
		glVertex3f(-absMaxX + length, -absMaxY, -absMaxZ);
		glVertex3f(-absMaxX, -absMaxY, -absMaxZ);
		glVertex3f(-absMaxX, -absMaxY + length, -absMaxZ);
		glVertex3f(-absMaxX, -absMaxY, -absMaxZ);
		glVertex3f(-absMaxX, -absMaxY, -absMaxZ + length);

		//back, lower right corner
		glVertex3f(absMaxX, -absMaxY, -absMaxZ);
		glVertex3f(absMaxX - length, -absMaxY, -absMaxZ);
		glVertex3f(absMaxX, -absMaxY, -absMaxZ);
		glVertex3f(absMaxX, -absMaxY + length, -absMaxZ);
		glVertex3f(absMaxX, -absMaxY, -absMaxZ);
		glVertex3f(absMaxX, -absMaxY, -absMaxZ + length);

		//back, upper left corner
		glVertex3f(-absMaxX, absMaxY, -absMaxZ);
		glVertex3f(-absMaxX + length, absMaxY, -absMaxZ);
		glVertex3f(-absMaxX, absMaxY, -absMaxZ);
		glVertex3f(-absMaxX, absMaxY - length, -absMaxZ);
		glVertex3f(-absMaxX, absMaxY, -absMaxZ);
		glVertex3f(-absMaxX, absMaxY, -absMaxZ + length);

		//back, upper right corner
		glVertex3f(absMaxX, absMaxY, -absMaxZ);
		glVertex3f(absMaxX - length, absMaxY, -absMaxZ);
		glVertex3f(absMaxX, absMaxY, -absMaxZ);
		glVertex3f(absMaxX, absMaxY - length, -absMaxZ);
		glVertex3f(absMaxX, absMaxY, -absMaxZ);
		glVertex3f(absMaxX, absMaxY, -absMaxZ + length);
	glEnd();

	//restart the lights
	glEnable(GL_LIGHTING);

	//reset GL_FRONT_AND_BACK mode
	glPolygonMode( GL_FRONT_AND_BACK, wireFrameMode );
}

void OGLVisu::createSphere()
{
	_sphereQuadric = gluNewQuadric();
}

//draw the representation of a directionnal light
void OGLVisu::drawDirectionnalLight(const CVector3f& direction)
{

	const float SPACE = 0.2f;

	//disable the lights
	glDisable(GL_LIGHTING);
	glLineWidth(5);
	glPushMatrix();
	glRotatef(-90, 1, 0, 0);

	glPushMatrix();
		glTranslatef(SPACE, 0, SPACE);
		glBegin(GL_LINES);
			glColor3f(1, 1, 1);
			glVertex3f(0, 0, 0);
			glVertex3f(0, -1, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(-0.2f, -0.9f, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(0.2f, -0.9f, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, 0.2f);

			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, -0.2f);
		glEnd();
	glPopMatrix();

	glPushMatrix();
		glTranslatef(-SPACE, 0, SPACE);
		glBegin(GL_LINES);
			glColor3f(1, 1, 1);
			glVertex3f(0, 0, 0);
			glVertex3f(0, -1, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(-0.2f, -0.9f, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(0.2f, -0.9f, 0);
			
			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, 0.2f);

			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, -0.2f);
		glEnd();
	glPopMatrix();

	glPushMatrix();
		glTranslatef(SPACE, 0, -SPACE);
		glBegin(GL_LINES);
			glColor3f(1, 1, 1);
			glVertex3f(0, 0, 0);
			glVertex3f(0, -1, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(-0.2f, -0.9f, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(0.2f, -0.9f, 0);
			
			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, 0.2f);

			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, -0.2f);
		glEnd();
	glPopMatrix();

	glPushMatrix();
		glTranslatef(-SPACE, 0, -SPACE);
		glBegin(GL_LINES);
			glColor3f(1, 1, 1);
			glVertex3f(0, 0, 0);
			glVertex3f(0, -1, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(-0.2f, -0.9f, 0);

			glVertex3f(0, -1, 0);
			glVertex3f(0.2f, -0.9f, 0);
			
			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, 0.2f);

			glVertex3f(0, -1, 0);
			glVertex3f(0, -0.9f, -0.2f);
		glEnd();
	glPopMatrix();
	glPopMatrix();
	//enable ligthing
	glEnable(GL_LIGHTING);
}	

//draw the representation of a point light
void OGLVisu::drawPointLight()const
{
	//disable the lights
	glDisable(GL_LIGHTING);
	glColor3f(1.f, 1.f, 1.f);
	gluSphere(_sphereQuadric, 0.5f, 10, 10);
	
	const int nbSubdivision = 10;
	for(int i = 0; i < nbSubdivision; i++)
	{
		float a = 360 / nbSubdivision * i;
		glPushMatrix();
			glRotatef(a, 1, 0, 0);
			glTranslatef(0, 1, 0);
			glBegin(GL_LINES);
				glVertex3f(0, 0.25f, 0);
				glVertex3f(0, -0.25f, 0);
			glEnd();
		glPopMatrix();
	}
	glEnable(GL_LIGHTING);
}

//draw the representation of a spot light
void OGLVisu::drawSpotLight()const
{

	//disable the lights
	glDisable(GL_LIGHTING);
	glColor3f(1.f, 1.f, 1.f);
	glPushMatrix();
		glRotatef(180, 1, 0, 0);
		gluCylinder(_discQuadric, 1, 0, 1.5, 10, 10);
		
		const int nbSubdivision = 10;
		for(int i = 0; i < 10; i++)
		{
			float a = 2 * 3.14f / 10.f * i;
			float cosA = cos(a);
			float sinA = sin(a);

			glPushMatrix();
				glBegin(GL_LINES);
					glVertex3f(cosA, sinA, -0.2);
					glVertex3f(cosA, sinA, -1.2);
				glEnd();
			glPopMatrix();
		}
		
	glPopMatrix();
	glEnable(GL_LIGHTING);
}

//draw the grid
void OGLVisu::drawGrid(const CVector3f& eye)const
{
	//calculate grid size
	float distance = abs(eye.y);

	const float treshold = 10;
	const int minimumLength = 50;
	float length = distance < treshold ? minimumLength : minimumLength+distance;
	float size = (int)length;

	glDisable(GL_LIGHTING);

	//draw grid
	glMatrixMode(GL_MODELVIEW);

	glPushMatrix();
	glTranslatef(floor(eye.x), 0, floor(eye.z));
	glLineWidth(2);
	glColor3f(0, 0, 0);
		for(int row = 0; row < size; row++)
		{
			float offset = -length/2 + row;
			glPushMatrix();
			glTranslatef(0, 0, offset);
			glBegin(GL_LINES);
				glColor3f(0, 0, 0);
				glVertex3f(-length/2, 0, 0);
				glVertex3f(length/2, 0, 0);
			glEnd();
			glPopMatrix();

			glPushMatrix();
			glTranslatef(offset, 0, 0);
			glBegin(GL_LINES);
				glColor3f(0, 0, 0);
				glVertex3f(0, 0, -length/2);
				glVertex3f(0, 0, length/2);
			glEnd();
			glPopMatrix();
		}
	glPopMatrix();

	glEnable(GL_LIGHTING);
}

//disable all the opengl source lights
void OGLVisu::disableUnusedLights(int nbUsed)const
{
	if (nbUsed == 8)
		return;

	int id = nbUsed - 1;

	for(int i = 7; i > id; i--)
		glDisable(GL_LIGHT0 + i);
}

//draw the representation of the camera
void OGLVisu::drawCamera()const
{
	//int wireframe = 0;
	//glGetIntegerv(GL_POLYGON_MODE, &wireframe);
	//glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );

	//disable lighting
	glDisable(GL_LIGHTING);

	//set the color
	glColor3f(1, 1, 1);

	glPushMatrix();
	glRotatef(180, 0, 1, 0);
	//start drawing
	glBegin(GL_QUADS);
		
		//top
		glVertex3f(0.3f, 0.3f, 0);
		glVertex3f(1, 0.8f, -1);
		glVertex3f(-1, 0.8f, -1);
		glVertex3f(-0.3f, 0.3f, 0);

		//left
		glVertex3f(-0.3f, 0.3f, 0);
		glVertex3f(-1, 0.8f, -1);
		glVertex3f(-1, -0.8f, -1);
		glVertex3f(-0.3f, -0.3f, 0);

		//right
		glVertex3f(0.3f, 0.3f, 0);
		glVertex3f(1, 0.8f, -1);
		glVertex3f(1, -0.8f, -1);
		glVertex3f(0.3f, -0.3f, 0);

		//bottom
		glVertex3f(0.3f, -0.3f, 0);
		glVertex3f(1, -0.8f, -1);
		glVertex3f(-1, -0.8f, -1);
		glVertex3f(-0.3f, -0.3f, 0);
	glEnd();

	glPopMatrix();

	glEnable(GL_LIGHTING);

	//glPolygonMode( GL_FRONT_AND_BACK, wireframe );
}